package com.example.lt.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.lt.constant.CommonConstant;
import com.example.lt.constant.MessageConstant;
import com.example.lt.constant.MinioPicPathConstant;
import com.example.lt.constant.PicPathConstant;
import com.example.lt.context.BaseContext;
import com.example.lt.exception.*;
import com.example.lt.mapper.ConsumerMapper;
import com.example.lt.mapper.OrdersMapper;
import com.example.lt.pojo.dto.*;
import com.example.lt.pojo.entity.Consumer;
import com.example.lt.pojo.entity.Orders;
import com.example.lt.pojo.vo.UserDetailVO;
import com.example.lt.pojo.vo.UserLoginVO;
import com.example.lt.pojo.vo.UserVO;
import com.example.lt.properties.JwtProperties;
import com.example.lt.result.Result;
import com.example.lt.service.ConsumerService;
import com.example.lt.service.MinioService;
import com.example.lt.utils.JwtUtil;
import com.example.lt.utils.RandomUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.example.lt.constant.CommonConstant.SALT;
import static com.example.lt.constant.CommonConstant.USER_ID;

/**
 * @Author 小涛Tao
 * @Date: 2024/05/29/17:54
 * version 1.0 注释：
 **/
@Service
@RequiredArgsConstructor
public class ConsumerServiceImpl extends ServiceImpl<ConsumerMapper, Consumer> implements ConsumerService {

    private final ConsumerMapper consumerMapper;

    private final OrdersMapper ordersMapper;

    private final RedisTemplate<String, Object> redisTemplate;

    private final MinioService minioService;

    private final JwtProperties jwtProperties;

    /**
     * 管理端获取所有用户信息
     * @return
     */
    public Result<List<UserDetailVO>> getAllUser() {
        List<Consumer> consumerList = consumerMapper.selectList(null);
        List<UserDetailVO> userDetailVOS = new ArrayList<>();
        for (Consumer consumer : consumerList) {
            UserDetailVO userDetailVO = BeanUtil.copyProperties(consumer, UserDetailVO.class);
            userDetailVOS.add(userDetailVO);
        }
        return Result.success(userDetailVOS);
    }

    /**
     * 管理端删除用户，永久删除的
     * @param id 用户id
     * @return
     */
    public Result deleteUser(Integer id) {
        int flag = consumerMapper.deleteById(id);
        if (flag > 0) {
            return Result.success(MessageConstant.DELETE_SUCCESS);
        } else {
            throw new AdminOperateException(MessageConstant.DELETE_FAIL);
        }
    }

    /**
     * 用户账号登录
     * @param userLoginDTO 用户登录信息：username、password
     * @return
     */
    public Result<List<UserLoginVO>> userLogin(UserLoginDTO userLoginDTO) {
        String username = userLoginDTO.getUsername();
        String password = userLoginDTO.getPassword();

        QueryWrapper<Consumer> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);

        Long num = consumerMapper.selectCount(queryWrapper); // 检查账号是否存在
        if (num < 1) {
            throw new LoginFailedException(MessageConstant.ACCOUNT_NOT_FOUND);
        }

        Consumer consumer = verifyPasswd(username, password, MessageConstant.PASSWORD_ERROR); // 自定义方法，验证密码是否正确

        List<UserLoginVO> tokenConsumer = getTokenConsumer(consumer); // 自定义方法，生成token并保存到UserLoginVO返回结果中

        return Result.success(MessageConstant.LOGIN_SUCCESS, tokenConsumer); // 登录成功，返回结果
    }

    /**
     * 用户邮箱登录
     * @param userLoginDTO 用户登录信息：email、password
     * @return
     */
    public Result<List<UserLoginVO>> emailLogin(UserLoginDTO userLoginDTO) {
        String email = userLoginDTO.getEmail();
        String password = userLoginDTO.getPassword();

        List<Consumer> consumers = lambdaQuery().eq(Consumer::getEmail, email).list();
        if (consumers.size() == 0) { // 验证该邮箱是否存在
            throw new LoginFailedException(MessageConstant.EMAIL_NOT_FOUND);
        }
        Consumer originalConsumer = consumers.get(0); // 获取数据库中对应的consumer
        Consumer consumer = verifyPasswd(originalConsumer.getUsername(), password, MessageConstant.PASSWORD_ERROR); // 自定义方法，验证密码是否正确

        List<UserLoginVO> tokenConsumer = getTokenConsumer(consumer); // 自定义方法，生成token并保存到UserLoginVO返回结果中

        return Result.success(MessageConstant.LOGIN_SUCCESS, tokenConsumer); // 登录成功，返回结果
    }

    /**
     * 注册账号
     * @param userRegisterDTO
     * @return
     */
    public Result register(UserRegisterDTO userRegisterDTO) {
        String password = userRegisterDTO.getPassword();
        if (password == null || "".equals(password)) { // 判断密码不能为空
            throw new UserUpdateException(MessageConstant.PASSWORD_IS_NULL);
        }

        String username = userRegisterDTO.getUsername();
        List<Consumer> consumers = lambdaQuery().eq(Consumer::getUsername, username).list();
        if (consumers.size() > 0) { // 检查该账号是否已存在
            throw new RegisterException(MessageConstant.ACCOUNT_EXIST);
        }
        if (checkEmail(userRegisterDTO.getEmail())) { // 检查此邮箱是否已存在
            throw new RegisterException(MessageConstant.EMAIL_EXIST);
        }

        String key = userRegisterDTO.getEmail();
        String code = (String) redisTemplate.opsForValue().get(key); // 从redis中拿出验证码来做验证
        if (code == null) {
            throw new RegisterException(MessageConstant.CODE_ERROR);
        }

        Consumer consumer = BeanUtil.copyProperties(userRegisterDTO, Consumer.class);
        // 给密码进行md5加密
        password = DigestUtils.md5DigestAsHex((SALT + password).getBytes());
        consumer.setPassword(password);
        consumer.setAvator(PicPathConstant.DEFAULT_AVATOR); // 设置注册时用户默认的头像

        int flag = consumerMapper.insert(consumer);
        if (!(flag > 0)) {
            throw new RegisterException(MessageConstant.REGISTER_FAIL);
        }

        return Result.success(MessageConstant.REGISTER_SUCCESS);
    }

    /**
     * 用户修改密码接口
     * @param updatePwdDTO 内含用户id、用户名、旧密码和新密码
     * @return
     */
    public Result updatePassword(UpdatePwdDTO updatePwdDTO) {
        String newPassword = updatePwdDTO.getPassword();
        if (newPassword == null || "".equals(newPassword)) { // 判断密码不能为空
            throw new UserUpdateException(MessageConstant.PASSWORD_IS_NULL);
        }

        String username = updatePwdDTO.getUsername(); // 拿出用户名
        String oldPassword = updatePwdDTO.getOldPassword(); // 拿出旧密码

        Consumer consumer = verifyPasswd(username, oldPassword, MessageConstant.OLD_PASSWORD_ERROR); // 自定义方法，验证密码是否正确

        newPassword = DigestUtils.md5DigestAsHex((SALT + newPassword).getBytes()); // 给密码进行加密
        consumer.setPassword(newPassword);

        int flag = consumerMapper.updateById(consumer); // 修改密码
        if (flag > 0) {
            return Result.success(MessageConstant.UPDATE_PASSWORD_SUCCESS);
        } else {
            throw new UserUpdateException(MessageConstant.UPDATE_PASSWORD_FAIL);
        }
    }

    /**
     * 用户重置密码
     * @param userResetPwdDTO
     * @return
     */
    public Result resetPassword(UserResetPwdDTO userResetPwdDTO) {
        String password = userResetPwdDTO.getPassword();
        if (password == null || "".equals(password)) {
            throw new UserUpdateException(MessageConstant.PASSWORD_IS_NULL);
        }
        String email = userResetPwdDTO.getEmail();
        String code = (String) redisTemplate.opsForValue().get(email);
        if (code == null || !code.equals(userResetPwdDTO.getCode())) {
            throw new UserUpdateException(MessageConstant.CODE_ERROR);
        }
        List<Consumer> consumers = lambdaQuery().eq(Consumer::getEmail, email).list();
        Consumer consumer = consumers.get(0);
        password = DigestUtils.md5DigestAsHex((SALT + password).getBytes());
        consumer.setPassword(password);

        int flag = consumerMapper.updateById(consumer);
        if (flag > 0) {
            return Result.success(MessageConstant.UPDATE_PASSWORD_SUCCESS);
        } else {
            throw new UserUpdateException(MessageConstant.UPDATE_PASSWORD_FAIL);
        }
    }

    /**
     * 根据用户id来获取用户信息
     * @param id
     * @return
     */
    public List<UserVO> getUserById(Integer id) {
        Consumer consumer = consumerMapper.selectById(id);
        UserVO userVO = BeanUtil.copyProperties(consumer,UserVO.class);
        List<UserVO> userVOS = new ArrayList<>();
        userVOS.add(userVO);
        return userVOS;
    }

    /**
     * 根据用户id获取用户详细信息
     * @param id
     * @return
     */
    public List<UserDetailVO> geUserDetail(Integer id) {
        Consumer consumer = consumerMapper.selectById(id);
        UserDetailVO userDetailVO = BeanUtil.copyProperties(consumer, UserDetailVO.class);
        List<UserDetailVO> userDetailVOS = new ArrayList<>();
        userDetailVOS.add(userDetailVO);
        return userDetailVOS;
    }

    /**
     * 把验证码存到redis中
     * @param key
     * @param code
     */
    public void redisSaveCode(String key, String code) {
        // 超时2分钟
        redisTemplate.opsForValue().set(key, code, 3, TimeUnit.MINUTES);
    }

    /**
     * 检查此邮箱是否有被用户注册过
     * @param email
     * @return true:已注册  false:未注册
     */
    public boolean checkEmail(String email) {
        List<Consumer> consumers = lambdaQuery() // 查询用户表中是否有email字段等于"email"的用户
                .eq(Consumer::getEmail, email)
                .list();
        if (consumers.size() > 0) {
            return true; // 此邮箱被注册了
        }
        return false; // 此邮箱还未被注册
    }

    /**
     * 更新用户头像，调用 minioService 中的方法添加与删除图片
     * @param avatorFile
     * @param id
     * @return
     */
    @Transactional
    public Result updateUserAvator(MultipartFile avatorFile, int id) {
        // 获取原来头像图片的名称，用于删除minio中原来的头像
        String originalPath = consumerMapper.selectById(id).getAvator();
        String originalName = originalPath.substring(originalPath.lastIndexOf("/") + 1);

        String fileName = RandomUtils.randomName(avatorFile.getOriginalFilename()); // 获取随机的文件名
        String imgPath = PicPathConstant.USER_AVATOR_PATH + fileName; // 获得新的头像路径
        Consumer consumer = Consumer.builder()
                .id(id)
                .avator(imgPath)
                .build();

        // 更新minio中的图片
        String s = minioService.uploadFile(MinioPicPathConstant.AVATOR_IMAGES_PATH, fileName, avatorFile);
        int flag = consumerMapper.updateById(consumer);

        if (!originalName.equals("default.png")) { // 删除原来在minion中的头像
            minioService.deleteFile(MinioPicPathConstant.AVATOR_IMAGES_PATH, originalName);
        }

        if (s.equals("File uploaded successfully.") && flag > 0) {
            return Result.success(MessageConstant.UPLOAD_AVATOR_SUCCESS, imgPath);
        } else {
            throw new MinioOperateException(MessageConstant.UPLOAD_AVATOR_FAIL);
        }
    }

    /**
     * 修改用户信息
     * @param userUpdateDTO
     * @return
     */
    public Result updateUserMsg(UserUpdateDTO userUpdateDTO) {
        String username = userUpdateDTO.getUsername();
        if (username.length() == 0) {
            throw new UserUpdateException(MessageConstant.USERNAME_IS_NULL);
        }

        List<Consumer> consumerList = lambdaQuery().eq(Consumer::getUsername, username).list(); // 修改列表中的用户名是否被主持过
        String originalName = consumerMapper.selectById(userUpdateDTO.getId()).getUsername(); // 获取原来的用户名
        if (consumerList.size() > 0 && !originalName.equals(username)) { // 用户名被注册了并且不是原来的用户名则抛出异常
            throw new UserUpdateException(MessageConstant.ALTER_FAIL + "," +MessageConstant.ACCOUNT_EXIST);
        }

        Consumer newConsumer = BeanUtil.copyProperties(userUpdateDTO, Consumer.class);
        int flag = consumerMapper.updateById(newConsumer);
        if (flag > 0) {
            return Result.success(MessageConstant.ALTER_SUCCESS);
        } else {
            throw new UserUpdateException(MessageConstant.ALTER_FAIL);
        }
    }

    /**
     * 注销用户
     * @param id
     * @return
     */
    public Result logOutUser(Integer id) {
        boolean flag = lambdaUpdate()
                .set(Consumer::getUsername, CommonConstant.UNREGISTERED_USERNAME)
                .set(Consumer::getAvator, PicPathConstant.UNREGISTERED_AVATOR_PATH)
                .set(Consumer::getEmail, null)
                .eq(Consumer::getId, id)
                .update();
        if (flag) {
            return Result.success(MessageConstant.LOGOFF_USER_SUCCESS);
        } else {
            throw new UserUpdateException(MessageConstant.LOGOFF_USER_FAIL);
        }
    }

    /**
     * 生成交易订单，并返回订单编号
     * @param duration
     * @return
     */
    public String recharge(String duration, Double total) {
        // 生成时间戳作为订单编号
        String format = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date(System.currentTimeMillis()));

        Orders orders = Orders.builder()
                .orderNo(format)
                .goodsName(duration + "月")
                .total(total)
                .status(0)
                .userId(BaseContext.getCurrentId())
                .build();

        int flag = ordersMapper.insert(orders);
        if (flag > 0){
            return format;
        }
        return null;
    }

    /**
     * 密码验证方法
     * @param username 用户名
     * @param password 密码
     * @return
     */
    public Consumer verifyPasswd(String username, String password, String message) {
        if (username.equals(CommonConstant.UNREGISTERED_USERNAME)) {
            throw new UsernameException(MessageConstant.USERNAME_ERROR);
        }
        // 创建条件构造器，并根据username查询用户Consumer
        QueryWrapper<Consumer> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        Consumer consumer = consumerMapper.selectOne(queryWrapper);

        // 密码比对：对前端传过来的明文密码进行md5加密处理后，再和数据库中密码比较
        password = DigestUtils.md5DigestAsHex((SALT + password).getBytes());
        if (!password.equals(consumer.getPassword())) { // 密码验证错误异常
            throw new VerifyPasswdErrorException(message);
        }

        return consumer;
    }

    /**
     * 获取添加了token后的UserLoginVO返回结果
     * @param consumer
     * @return
     */
    public List<UserLoginVO> getTokenConsumer(Consumer consumer) {
        //登录成功后，生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put(USER_ID, consumer.getId());
        String token = JwtUtil.createJWT(
                jwtProperties.getLoginSecretKey(),
                jwtProperties.getLoginTtl(),
                claims
        );

        UserLoginVO userLoginVO = UserLoginVO.builder() // 创建返回结果
                .id(consumer.getId())
                .username(consumer.getUsername())
                .avator(consumer.getAvator())
                .token(token)
                .build();

        List<UserLoginVO> list = new ArrayList<>(); // 因为前端的问题，结果要封装到list集合中
        list.add(userLoginVO);
        return list;
    }

}
